﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Collections;
using DevExpress.Data;
using ChinaDynastyTours.Helpers;

namespace ChinaDynastyTours.Views
{
    public partial class FilesSelectForm : DevExpress.XtraEditors.XtraForm
    {
        public string ReturnValues { get; set; }

        public FilesSelectForm()
        {
            InitializeComponent();

            this.fileCollection = new FileCollection(ApplicationHelper.AbsolutelyContractPath);
            this.gridControl1.DataSource = this.fileCollection;
            this.gridColumnImage.Caption = " ";
            //ChangeFolderPath(ApplicationHelper.AbsolutelyContractPath);
            labelCurrentPath.Text = ApplicationHelper.AbsolutelyContractPath;
        }


        FileCollection fileCollection;
 
        private void gridView1_MouseDown(object sender, System.Windows.Forms.MouseEventArgs e)
        {
            if (e.Clicks > 1)
            {
                DevExpress.XtraGrid.Views.Grid.ViewInfo.GridHitInfo hitInfo = this.gridView1.CalcHitInfo(new Point(e.X, e.Y));
                if (hitInfo.InRow)
                    ChangedFolderPath();
            }
        }
        private void gridView1_KeyDown(object sender, System.Windows.Forms.KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Enter)
                ChangedFolderPath();
        }
        void ChangedFolderPath()
        {
            //如果选择的是“..”并且当前路径是根路径，则不允许进入上级目录
            string floderName = gridView1.GetRowCellValue(gridView1.FocusedRowHandle, "Name").ToString();
            if (labelCurrentPath.Text == ApplicationHelper.AbsolutelyContractPath && floderName == "..")
                return;

            int rowIndex = gridView1.ViewRowHandleToDataSourceIndex(this.gridView1.FocusedRowHandle);
            if ((rowIndex < 0) || (this.fileCollection[rowIndex].ItemType == FileCollectionItemType.File))
                return;
            string newPath = this.fileCollection[rowIndex].ItemType == FileCollectionItemType.Up ?
                this.fileCollection[rowIndex].DirectoryName : string.Empty;
            ChangeFolderPath(this.fileCollection[rowIndex].FullName);
        }
        void ChangeFolderPath(string newPath)
        {
            this.gridView1.BeginUpdate();
            try
            {
                this.fileCollection.FilePath = newPath;
                ((CurrencyManager)this.gridControl1.BindingContext[this.fileCollection]).Refresh();
                int focusedIndex = newPath != string.Empty ? this.fileCollection.IndexOf(newPath) : 0;
                if (focusedIndex < 0)
                    focusedIndex = 0;
                this.gridView1.FocusedRowHandle = focusedIndex;
                this.labelCurrentPath.Text = this.fileCollection.FilePath;
            }
            finally
            {
                this.gridView1.EndUpdate();
            }
        }

        private void gridView1_CustomDrawCell(object sender, DevExpress.XtraGrid.Views.Base.RowCellCustomDrawEventArgs e)
        {
            int rowIndex = gridView1.ViewRowHandleToDataSourceIndex(e.RowHandle);
            if (e.Column == this.gridColumnSize)
            {
                if (this.fileCollection[rowIndex].ItemType == FileCollectionItemType.File)
                {
                    long size = this.fileCollection[rowIndex].Size;
                    if (size >= 1024)
                        e.DisplayText = string.Format("{0:### ### ###} KB", size / 1024);
                    else e.DisplayText = string.Format("{0} Bytes", size);
                }
                else e.DisplayText = string.Empty;
            }
            if (e.Column == this.gridColumnModified)
            {
                if (this.fileCollection[rowIndex].ItemType == FileCollectionItemType.Up)
                    e.DisplayText = string.Empty;
            }
        }

        private void gridView1_CalcPreviewText(object sender, DevExpress.XtraGrid.Views.Grid.CalcPreviewTextEventArgs e)
        {
            e.PreviewText = ((FileCollectionItem)gridView1.GetRow(e.RowHandle)).FullName;
        }

        int FolderComparer(FileCollectionItem item1, FileCollectionItem item2)
        {
            if (item1.ItemType != item2.ItemType)
            {
                if (item1.ItemType == FileCollectionItemType.Up) return -1;
                if (item2.ItemType == FileCollectionItemType.Up) return 1;
                if (item1.ItemType == FileCollectionItemType.Directory) return -1;
                if (item2.ItemType == FileCollectionItemType.Directory) return 1;
            }
            return 0;
        }

        bool IsFolder(FileCollectionItem item1)
        {
            if (item1.ItemType == FileCollectionItemType.Up) return true;
            if (item1.ItemType == FileCollectionItemType.Directory) return true;
            return false;
        }

        private void gridView1_CustomColumnSort(object sender, DevExpress.XtraGrid.Views.Base.CustomColumnSortEventArgs e)
        {
            FileCollectionItem item1 = e.RowObject1 as FileCollectionItem, item2 = e.RowObject2 as FileCollectionItem;
            int res = FolderComparer(item1, item2);
            if (res == 0)
            {
                res = Comparer.Default.Compare(e.Value1, e.Value2);
                if (e.Column != gridColumnName && e.Column != gridColumnModified)
                {
                    if (IsFolder(item1))
                    {
                        res = Comparer.Default.Compare(item1.Name, item2.Name);
                        if (res != 0 && e.SortOrder == ColumnSortOrder.Descending)
                            res = res > 0 ? -1 : 1;

                        e.Result = res;
                        e.Handled = true;
                        return;
                    }
                }
            }
            else
            {
                if (res != 0 && e.SortOrder == ColumnSortOrder.Descending) res = res > 0 ? -1 : 1;
            }
            e.Result = res;
            e.Handled = true;
        }
        private void FilesSelectFloderForm_Load(object sender, EventArgs e)
        {
            gridView1.FocusedRowHandle = 0;
        }

        private void btnOk_Click(object sender, EventArgs e)
        {
            foreach (int rowId in this.gridView1.GetSelectedRows())
            {
                if(ReturnValues!=null)
                    ReturnValues = string.Format("{0};{1}\\{2}", ReturnValues, labelCurrentPath.Text.Replace(ApplicationHelper.AbsolutelyContractPath, ""), gridView1.GetRowCellValue(rowId, "Name").ToString());
                else
                    ReturnValues = string.Format("{0}\\{1}", labelCurrentPath.Text.Replace(ApplicationHelper.AbsolutelyContractPath,""), gridView1.GetRowCellValue(rowId, "Name").ToString());
            }
        }

        #region FilesDir
        public class Directories : ArrayList, DevExpress.Data.IRelationList
        {
            public Directories(string root)
            {
                string[] s = System.IO.Directory.GetDirectories(root);
                for (int i = 0; i < s.Length; i++)
                    Add(new Directory(i, s[i]));
            }

            //IRelationList
            string IRelationList.GetRelationName(int index, int relationIndex)
            {
                return (relationIndex == 0 ? "Directories" : "Files");
            }

            int IRelationList.RelationCount
            {
                get { return 2; }
            }

            bool IRelationList.IsMasterRowEmpty(int index, int relationIndex)
            {
                return this[index].MasterDetail(relationIndex);
            }

            IList IRelationList.GetDetailList(int index, int relationIndex)
            {
                IList list;
                string rootDir = ((Directory)this[index]).FullName;
                if (relationIndex == 0)
                    list = new Directories(rootDir);
                else
                    list = new Files(rootDir);
                return (list.Count > 0 ? list : null);
            }
            //IRelationList end

            public virtual new Directory this[int index]
            {
                get { return (Directory)(base[index]); }
            }
        }

        public class Files : ArrayList
        {
            public Files(string dir)
            {
                string[] s = System.IO.Directory.GetFiles(dir);
                for (int i = 0; i < s.Length; i++)
                    Add(new File(s[i]));
            }
        }

        public class Directory
        {
            private int fid;
            private string fname;
            private int ffilesCount = -1;
            private int fchildDirCount = -1;
            internal System.IO.DirectoryInfo dInfo;

            internal Directory(int fid, string fname)
            {
                this.fid = fid;
                this.fname = fname;
                dInfo = new System.IO.DirectoryInfo(this.fname);
            }

            public bool MasterDetail(int relationIndex)
            {
                bool ret = true;
                try
                {
                    if (relationIndex == 0)
                        ret = !(System.IO.Directory.GetDirectories(fname).Length > 0);
                    else
                        ret = !(System.IO.Directory.GetFiles(fname).Length > 0);
                }
                catch { }
                return ret;
            }

            private int ID
            {
                get { return fid; }
            }

            public string FullName
            {
                get { return fname; }
            }
            public string Name
            {
                get { return dInfo.Name; }
            }
            public DateTime CreationTime
            {
                get { return dInfo.CreationTime; }
            }
            public int FilesCount
            {
                get
                {
                    if (ffilesCount == -1)
                    {
                        ffilesCount = 0;
                        try
                        {
                            ffilesCount = System.IO.Directory.GetFiles(fname).Length;
                        }
                        catch { }
                    }
                    return ffilesCount;
                }
            }
            public int ChildDirCount
            {
                get
                {
                    if (fchildDirCount == -1)
                    {
                        fchildDirCount = 0;
                        try
                        {
                            fchildDirCount = System.IO.Directory.GetDirectories(fname).Length;
                        }
                        catch { }
                    }
                    return fchildDirCount;
                }
            }
            public string Attributes
            {
                get { return MyFileAttributes.StringFileAttributes(dInfo.Attributes); }
            }
        }

        public class File
        {
            internal System.IO.FileInfo fInfo;
            internal File(string fname)
            {
                fInfo = new System.IO.FileInfo(fname);
            }
            public string Name
            {
                get { return fInfo.Name; }
            }
            public long Length
            {
                get { return fInfo.Length; }
            }
            public DateTime CreationTime
            {
                get { return fInfo.CreationTime; }
            }
            public DateTime LastWriteTime
            {
                get { return fInfo.LastWriteTime; }
            }
            public DateTime LastAccessTime
            {
                get { return fInfo.LastAccessTime; }
            }
            public string Attributes
            {
                get { return MyFileAttributes.StringFileAttributes(fInfo.Attributes); }
            }
        }

        internal class MyFileAttributes
        {
            internal static string StringFileAttributes(System.IO.FileAttributes fa)
            {
                string s = "";
                if ((System.IO.FileAttributes.Archive & fa) != 0)
                    s += "-A";
                if ((System.IO.FileAttributes.Compressed & fa) != 0)
                    s += "-C";
                if ((System.IO.FileAttributes.Normal & fa) != 0)
                    s += "-N";
                if ((System.IO.FileAttributes.Hidden & fa) != 0)
                    s += "-H";
                if ((System.IO.FileAttributes.ReadOnly & fa) != 0)
                    s += "-RO";
                if ((System.IO.FileAttributes.System & fa) != 0)
                    s += "-S";
                if ((System.IO.FileAttributes.Temporary & fa) != 0)
                    s += "-Tmp";
                s += "-";
                return s;
            }
        }

        #endregion

        #region GridFolder
        public enum FileCollectionItemType { Up = 0, File, Directory };
        public class FileCollectionItem
        {
            FileCollectionItemType fitemType;
            string fname, fdisplayName;
            long ffileSize;
            DateTime fmodified;

            public FileCollectionItem(FileCollectionItemType fitemType, string fname)
            {
                this.fitemType = fitemType;
                this.fname = fname;
                this.fdisplayName = ItemType != FileCollectionItemType.Up ? System.IO.Path.GetFileName(fname) : "..";
                this.ffileSize = -1;
            }
            public FileCollectionItemType ItemType { get { return this.fitemType; } }
            public string Name { get { return this.fdisplayName; } }
            public string FullName
            {
                get
                {
                    return ItemType == FileCollectionItemType.Up ?
                        System.IO.Path.GetDirectoryName(this.fname) : this.fname;
                }
            }
            public string DirectoryName
            {
                get
                {
                    return ItemType != FileCollectionItemType.Up ?
                        System.IO.Path.GetDirectoryName(this.fname) : this.fname;
                }
            }
            public int ImageIndex { get { return (int)ItemType - 1; } }
            public long Size
            {
                get
                {
                    if (ItemType == FileCollectionItemType.File)
                    {
                        UpdateFileInfo();
                        return this.ffileSize;
                    }
                    else return 0;
                }
            }
            public DateTime Modified
            {
                get
                {
                    if (ItemType == FileCollectionItemType.File)
                    {
                        UpdateFileInfo();
                        return this.fmodified;
                    }
                    else
                    {
                        UpdateDirInfo();
                        return this.fmodified;
                    }
                }
            }
            void UpdateFileInfo()
            {
                if (this.ffileSize >= 0) return;
                System.IO.FileInfo fileInfo = new System.IO.FileInfo(this.fname);
                this.ffileSize = fileInfo.Length;
                this.fmodified = fileInfo.LastWriteTime;
            }
            void UpdateDirInfo()
            {
                System.IO.DirectoryInfo dirInfo = new System.IO.DirectoryInfo(this.fname);
                this.fmodified = dirInfo.LastWriteTime;
            }
        }
        class FileCollection : ArrayList
        {
            string ffilePath;
            public FileCollection(string ffilePath)
            {
                FilePath = ffilePath;
            }
            public string FilePath
            {
                get { return ffilePath; }
                set
                {
                    if (FilePath == value) return;
                    Clear();
                    this.ffilePath = value;
                    if (System.IO.Path.GetFileName(value) != string.Empty)
                        Add(new FileCollectionItem(FileCollectionItemType.Up, value));
                    try
                    {
                        string[] dirs = System.IO.Directory.GetDirectories(ffilePath);
                        for (int i = 0; i < dirs.Length; i++)
                            Add(new FileCollectionItem(FileCollectionItemType.Directory, dirs[i]));
                        string[] files = System.IO.Directory.GetFiles(ffilePath);
                        for (int i = 0; i < files.Length; i++)
                            Add(new FileCollectionItem(FileCollectionItemType.File, files[i]));
                    }
                    catch
                    {
                    }
                }
            }
            public new FileCollectionItem this[int index] { get { return base[index] as FileCollectionItem; } }
            public int IndexOf(string path)
            {
                for (int i = 0; i < Count; i++)
                    if (path.Equals(this[i].FullName)) return i;
                return -1;
            }
        }
        #endregion

    }
}
